
package bankservice.endpoint;

import java.net.*;
import java.io.*;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService(endpointInterface = "bankservice.endpoint.BankInterface")

/**  
 *
 * This class implements a bank branch with 20 accounts.
 *
 * Its main attribute is :branchCode
 * 
 * It has four main methods: deposit, withdraw, getBalance and transfer 
 *   
 * @author g_ogha
 *
 */


public class BankImpl implements BankInterface {

	private String branchCode;	
	
	private int numberOfBankAccounts;
	public static BankAccountImpl bankAccounts[];
			
	public BankImpl() {
    	
    	super( );
    	numberOfBankAccounts = 0;
    	
   	}
	
	// This method creates one bank account for this branch
	
	 @WebMethod() 
	public void createBankAccount() {
		
		numberOfBankAccounts = numberOfBankAccounts + 1;	
		bankAccounts[numberOfBankAccounts]= new BankAccountImpl();
		
    }
	 
	 @WebMethod()
	public BankAccountImpl  getBankAccount(int i) {
			
		return bankAccounts[i]; 
		
    }
	
	// This method creates 20 accounts for this branch    
	
	 @WebMethod()
	public void initializeBank() {
		
		String accNumber;
		
		bankAccounts = new  BankAccountImpl[20];
		
		for (int i=1; i < 20; i++){
			
			accNumber = Integer.toString(i);
	        if (accNumber.length()== 1 )
	        	accNumber = "00" + accNumber;
	        else if (accNumber.length()== 2 )
	        	accNumber = "0" + accNumber;
	        
			this.createBankAccount();
			bankAccounts[numberOfBankAccounts].setAccountNumber(accNumber);
			bankAccounts[numberOfBankAccounts].setAccountHolder("Name"+i);
			bankAccounts[numberOfBankAccounts].setAddress("Address"+i);			
		}    
    }
	
	 @WebMethod()
	public int getNumberOfBankAccounts() {
		
    	return numberOfBankAccounts;
   	}
	
	 @WebMethod()
	public String getBranchCode() {
		
    	return branchCode;
   	}
	
	 @WebMethod()
	public void setBranchCode(String bCode)  {
		 	
    	branchCode = bCode;
   	}
	
	 @WebMethod()
	public void deposite(String accountNumber,float amount) {
		
		String accIndex = accountNumber.substring(2,5);
		int accountIndex = Integer.parseInt(accIndex);
						
		bankAccounts[accountIndex].deposite(accountNumber, amount);
   	}
	
	 @WebMethod()
	public void withdraw(String accountNumber,float amount){
			
		String accIndex = accountNumber.substring(2,5);
		int accountIndex = Integer.parseInt(accIndex);
		
		bankAccounts[accountIndex].withdraw(accountNumber, amount);		
   	}
	
	 @WebMethod()
	public float getBalance(String accountNumber){
		
		String accIndex = accountNumber.substring(2,5);
		int accountIndex = Integer.parseInt(accIndex);
		
		return bankAccounts[accountIndex].getBalance(accountNumber);
   	}
	
	/* This method sends a request for deposit to destination branch through UDP
	 * waits for reply. if the reply was successful , withdraw will be done otherwise 
	 * it rolls back.
	 * 
	*/
	
	 @WebMethod()
	public float transfer(String sourceAccountNumber,String destinationAccountNumber,float amount){
		
		float returnValue = 0;		
						
		String accIndex = sourceAccountNumber.substring(2,5);
		int sourceIndex = Integer.parseInt(accIndex);
				
		accIndex = destinationAccountNumber.substring(2,5);
		int destinationIndex = Integer.parseInt(accIndex);
		
		String bankCode = destinationAccountNumber.substring(0,2);
		int destinationCode = Integer.parseInt(bankCode);
		
		bankAccounts[sourceIndex].setTempTransferAmount(amount);
		
		if (sourceAccountNumber.substring(0,2).equals(destinationAccountNumber.substring(0,2))){
						
			bankAccounts[destinationIndex].deposite(destinationAccountNumber, amount);
			bankAccounts[sourceIndex].withdraw(sourceAccountNumber, amount);
		}
		else{
		
			DatagramSocket aSocket = null;
			int listenerPort = 0;
			
			String replyData = "" ;
		
			try {
				
				aSocket = new DatagramSocket();
			
				Float floatObject = new Float(amount);
			
				String  data = destinationAccountNumber + floatObject.toString();
		
				byte [] m = data.getBytes();
						
				InetAddress aHost = InetAddress.getByName("localhost");
			
				if (destinationCode == 1){
					listenerPort = 6000;
				}	
				else if (destinationCode == 2){
					listenerPort = 6500;
				}
					
				DatagramPacket request = new DatagramPacket(m,data.length(), aHost, listenerPort);
				
				// sending the request
			
				aSocket.send(request);			                        
			
				byte[] buffer = new byte[1000];
				DatagramPacket reply = new DatagramPacket(buffer, buffer.length);
			
				aSocket.receive(reply);
				
				// waiting for reply
				
				replyData = new String(reply.getData());	
								
			}catch (SocketException e){System.out.println("Socket Error: " + e.getMessage());
			}catch (IOException e){System.out.println("IO Error: " + e.getMessage());
			}finally {if(aSocket != null) aSocket.close();}// end of try-catch
			
			// Withdrawing from account
			
			if (!(replyData.substring(0, 5).equals("ERROR"))){
				
				bankAccounts[sourceIndex].withdraw(sourceAccountNumber, amount);
				
				bankAccounts[sourceIndex].setTempTransferAmount(0);
				
				returnValue = bankAccounts[sourceIndex].getBalance(sourceAccountNumber);
			}
			else  //Rolling back
			{
				bankAccounts[sourceIndex].setTempTransferAmount(0);
				returnValue = -1;				
			}
			
		}// end of if
				
		return   returnValue ;
		
	}// end of transfer
	
}// end of class
	

